open Prettyprint

let infile_name = ref None
let outformat = ref None
let outfile_name = ref None


let infile = ref stdin
exception No_input_file of string
exception Parse_error of string
exception Undefined_format_error of string

(* Parsing command line arguments using Arg module. Sets the variables infile_name, outfile_name and outformat. *)
let usage = "usage: " ^ "bp2bfg" ^ " [-i string] [-o string] [-format string]";; 		

let speclist = [
  ("-i", Arg.String   (fun s -> infile_name := Some s), ": Sets the input file, optional, default is stdin.");
  ("-o", Arg.String (fun s -> outfile_name := Some s), ": Sets the output file name (i.e. file ending exluded), optional, default is stdout.");
	("-format", Arg.String (fun s -> outformat := Some s), ": Sets the output format. One of: \n\t[bp] concrete Boolean program without syntactic sugar, i.e. simplified.\n\t[lbp] As bp but with labels.\n\t[lobp] Boolean program annotated with locations.\n\t[bfg] Boolean flow graph, the default.\n\t[dot] The dot-language, a textual representation of a (Boolean flow) graph.\n\t[prep] Preprocesses a Boolean program.");
  ]
  
let () = Arg.parse speclist (fun x -> raise (Arg.Bad ("Bad argument : " ^ x))) usage;;
(* End of command line parsing *)

let parse infile = 
  let lexbuf = Lexing.from_channel infile in
    try 
      Parser.bp Lexer.token lexbuf
    with exn ->
      let curr = lexbuf.Lexing.lex_curr_p in
      let line = curr.Lexing.pos_lnum in
      let cnum = curr.Lexing.pos_cnum - curr.Lexing.pos_bol in
      let tok = Lexing.lexeme lexbuf in
      raise (Parse_error ("(Position: " ^ (string_of_int line) ^ ":" ^ (string_of_int cnum) ^ ", Token: " ^ tok ^ ")"))
	;;

(* different printFunction depending on program flags *)
let handle bp = let Ast.Bp(decl, procs) = bp in 
	match !outformat with
		None -> Format.printf "%s" "write boolean flow graph"
		| Some "bp" -> setFormatterOutChannel "bp" !outfile_name; printCode decl procs
		| Some "lbp" -> setFormatterOutChannel "lbp" !outfile_name; printWithLabels decl procs
		| Some "lobp" -> setFormatterOutChannel "lobp" !outfile_name; printWithLocations decl procs
		| Some "bfg" -> setFormatterOutChannel "bfg" !outfile_name; printFlowGraph decl procs
		| Some "dot" -> setFormatterOutChannel "dot" !outfile_name; printDot decl procs
    | Some "prep" -> setFormatterOutChannel "bp" !outfile_name; printPreprocessed decl procs
		| _ -> raise(Undefined_format_error("The output format you have given is not a valid output format. Valid formats are bp/lbp/lobp/bfg/dot."))
		;;

let read_file infile_name = 
  let infile =
    match !infile_name with 
      | None -> 
        stdin      
      | Some s -> 
        open_in s
  in 
    let bp = parse infile in
      (handle bp)
  ;;

try read_file infile_name with
	| No_input_file e -> output_string stderr (e ^ "\n" ^ usage)
	| End_of_file -> output_string stderr "Parsning klar!"
	| Parse_error s -> output_string stderr ("Parsing error: Syntax error or illegal character sequence at: " ^ s)
	| Undefined_format_error s -> output_string stderr s
	| Sys_error e -> output_string stderr ("File handling error for: " ^ e)
	;;